package redis.lock.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Service;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author guo
 */
@Service
public class LockService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;




    public boolean lock(String key, String value, long expireTime) {
        boolean success = stringRedisTemplate.execute((RedisCallback<Boolean>) connection ->
                connection.set(key.getBytes(),value.getBytes(),Expiration.from(expireTime,TimeUnit.MILLISECONDS), RedisStringCommands.SetOption.SET_IF_ABSENT));
        return success;
    }



    public boolean unLock(String key, String value){
        String lua = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        DefaultRedisScript<Long> script = new DefaultRedisScript(lua, Long.class);
        List<String> keys = new ArrayList<>();
        keys.add(key);
        long result = stringRedisTemplate.execute(script, new StringRedisSerializer(), new RedisSerializer<Long>() {
            private final Charset charset = Charset.forName("UTF8");
            @Override
            public byte[] serialize(Long aLong) throws SerializationException {
                return (aLong == null ? null : (aLong.toString()).getBytes(charset));
            }
            @Override
            public Long deserialize(byte[] bytes) throws SerializationException {
                return (bytes == null ? null : Long.parseLong(new String(bytes, charset)));
            }
        }, keys, value);
        if (1==result) {
            return true;
        }
        return false;
    }

}
